﻿/******************************************************
* author :  cwj
* email  :  chenwenji_360@live.com 
* history:  created by cwj 2015/7/16 16:27:52 
* clrversion :4.0.30319.18444
******************************************************/

using Machine.DataAccess.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace Machine.DataAccess.Common.ORM
{
    class OrmHelper
    {
        //private static Lazy<OrmHelper> _instance = new Lazy<OrmHelper>(() =>
        //{
        //    return new OrmHelper();
        //}, true);
        //public static OrmHelper Instance { get { return _instance.Value; } }
        //private OrmHelper() { }

        private Dictionary<Type, object> map = new Dictionary<Type, object>();

        public OrmType GetTypeCode(Type type)
        {
            var typeCode = Type.GetTypeCode(type);
            var ormType = OrmType.None;
            if (type.Name.StartsWith("<>")) ormType = OrmType.UnKnowType;
            else if (typeCode == TypeCode.Object && type != typeof(Guid)) ormType = OrmType.KnowType;
            else ormType = OrmType.Basic;
            return ormType;
        }

        public TResult GetResult<TResult>(IDataReader reader, ProviderElement providerElement, OrmType ormType = OrmType.None)
        {
            var type = typeof(TResult);
            if (ormType == OrmType.None) ormType = this.GetTypeCode(type);
            if (type.Name == typeof(object).Name) ormType = OrmType.Basic;
            object temp = null;
            switch (ormType)
            {
                case OrmType.Basic:
                    temp = GetBasic(reader, 0, type);
                    break;
                case OrmType.KnowType:
                    temp = this.GetKnow(reader, type, providerElement,null);
                    break;
                case OrmType.UnKnowType:
                    temp = this.GetUnKnow(reader, type, providerElement);
                    break;
                default:
                    throw new NotSupportedException("不支持的类型");
            }
            return temp == null ? default(TResult) : (TResult)temp;
        }

        public object GetResult(IDataReader reader, object obj, ProviderElement providerElement, OrmType ormType = OrmType.None)
        {
            var type = obj.GetType();
            if (ormType == OrmType.None) ormType = this.GetTypeCode(type);
            switch (ormType)
            {
                case OrmType.Basic:
                    return GetBasic(reader, 0, type);
                case OrmType.KnowType:
                    return this.GetKnow(reader, type, providerElement,null);
                case OrmType.UnKnowType:
                    return this.GetUnKnow(reader, type, providerElement);
                default:
                    throw new NotSupportedException("不支持的类型");
            }
            throw new NotImplementedException();
        }

        //public TResult GetResult<TResult>(object obj, OrmType ormType = OrmType.None)
        //{
        //    var type = typeof(TResult);
        //    if (ormType == OrmType.None) ormType = this.GetTypeCode(type);
        //    switch (ormType)
        //    {
        //        case OrmType.Basic:
        //            return (TResult)GetBasic(obj, type);
        //        case OrmType.KnowType:
        //            return (TResult)this.GetKnow(obj, typeof(TResult));
        //        case OrmType.UnKnowType:
        //            throw new NotSupportedException("暂时不支持");
        //        //return (TResult)this.GetUnKnow(reader, typeof(TResult));
        //        default:
        //            throw new NotSupportedException("不支持的类型");
        //    }
        //    throw new NotImplementedException();
        //}

        private object GetKnow(IDataReader reader, Type type,ProviderElement providerElement,Type baseType)
        {
            //if (type.IsInterface) throw new NotSupportedException("暂时不支持集合类型");
            object obj = Activator.CreateInstance(type);
            var properties = DynamicAssignment.Instance.GetDictionary(type);
            var relpaceName = baseType == null ? type.Name.ToLower() :
                string.Format("{0}{1}", baseType.Name.ToLower(), type.Name.ToLower());
            for (int i = 0; i < reader.FieldCount; i++)
            {
                //var dbName = reader.GetName(i).ToLower().Replace(type.Name.ToLower(), "");
                var dbName = reader.GetName(i).ToLower().Replace(relpaceName, "");
                if (properties.ContainsKey(dbName) && !reader.IsDBNull(i))
                {
                    if (obj == null) obj = Activator.CreateInstance(type);
                    var property = properties[dbName];
                    var propertyType = property.PropertyInfo.PropertyType;
                    object value = GetBasic(reader, i, property.PropertyInfo.PropertyType);
                    properties[dbName].SetValue(obj, value);
                }

            }
            this.map[type] = obj;
            //if (obj == null) return obj;
            var objProperties = properties.Where(x => 
                Type.GetTypeCode(x.Value.PropertyInfo.PropertyType) == TypeCode.Object && 
                (x.Value.PropertyInfo.PropertyType != typeof(Guid) && x.Value.PropertyInfo.PropertyType != typeof(byte[])));
            foreach (var property in objProperties)
            {
                var propertyType = property.Value.PropertyInfo.PropertyType;
                object value = this.map.ContainsKey(propertyType) && !propertyType.IsGenericType ?
                    this.map[propertyType] : GetKnow(reader, propertyType,providerElement,type);
                if (propertyType.IsGenericType)
                {
                    var gernericParameter = propertyType.GetGenericArguments().FirstOrDefault();
                    var createType = typeof(DataReader<>).MakeGenericType(gernericParameter);
                    var translator = new ReaderFormat(providerElement).Format(obj,gernericParameter);//Config.Instance.GetFormatVistor(providerElement).Format(obj, gernericParameter);
                    value = Activator.CreateInstance(createType, translator, providerElement,this.map[type], CommandType.Text);
                }
                property.Value.SetValue(obj, value);
            }
            return obj;
        }
        //private object GetKnow(object reader, Type type)
        //{
        //    var obj = Activator.CreateInstance(type);
        //    var properties = DynamicAssignment.Instance.GetDictionary(type);
        //    foreach (var property in properties)
        //    {
        //        property.Value.SetValue(obj, property.Value.GetValue(property.Key));
        //    }
        //    return obj;
        //}

        private object GetUnKnow(IDataReader reader, Type type,ProviderElement providerElement)
        {
            var properties = type.GetProperties();
            var list = new List<object>();
            foreach (var property in properties)
            {
                var typeCode = this.GetTypeCode(property.PropertyType);
                switch (typeCode)
                {
                    case OrmType.Basic:
                        //list.Add(reader[property.Name]);
                        var index = reader.GetOrdinal(property.Name);
                        list.Add(GetBasic(reader, index, property.PropertyType));
                        break;
                    case OrmType.KnowType:
                        list.Add(GetKnow(reader, property.PropertyType,providerElement,null));
                        break;
                    default:
                        throw new NotSupportedException("不支持的类型");
                }
            }
            return Activator.CreateInstance(type, list.ToArray());
        }

        private object GetBasic(IDataReader reader, int index,Type type)
        {
            if (type == typeof(Guid) && !reader.IsDBNull(index)) return reader.GetGuid(index);
            if (type == typeof(byte[]) && !reader.IsDBNull(index)) return (byte[])reader.GetValue(index);
            if (type == typeof(object)) return reader.GetValue(index);
            if (reader.IsDBNull(index)) return null;
            var typeCode = Type.GetTypeCode(type);
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return reader.GetBoolean(index);
                case TypeCode.Byte:
                    return reader.GetByte(index);
                case TypeCode.Char:
                    return reader.GetString(index);
                case TypeCode.DBNull:
                    if (type.IsClass) return null; else return Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(type));
                case TypeCode.DateTime:
                    return reader.GetDateTime(index);
                case TypeCode.Decimal:
                    return reader.GetDecimal(index);
                case TypeCode.Double:
                    return reader.GetDouble(index);
                case TypeCode.Empty:
                    if (type.IsClass) return null; else return Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(type));
                case TypeCode.Int16:
                    return reader.GetInt16(index);
                case TypeCode.Int32:
                    return reader.GetInt32(index);
                case TypeCode.Int64:
                    return reader.GetInt64(index);
                case TypeCode.Object:
                    throw new NotSupportedException("数据库转化类型异常");
                case TypeCode.SByte:
                    return reader.GetByte(index);
                case TypeCode.Single:
                    return reader.GetFloat(index);
                case TypeCode.String:
                    return reader.GetString(index);
                case TypeCode.UInt16:
                    return reader.GetInt16(index);
                case TypeCode.UInt32:
                    return reader.GetInt32(index);
                case TypeCode.UInt64:
                    return reader.GetInt64(index);
                default:
                    throw new NotSupportedException(string.Format("未处理的数据类型:{0}", type));
            }
        }

        public static object GetBasic<TResult>(object obj)
        {
            if (obj == null) return default(TResult);
            var type = typeof(TResult);
            if (type == typeof(Guid)) return Guid.Parse(obj.ToString());
            var typeCode = Type.GetTypeCode(type);
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return bool.Parse(obj.ToString());//reader.GetBoolean(index);
                case TypeCode.Byte:
                case TypeCode.SByte:
                    return byte.Parse(obj.ToString());//reader.GetByte(index);
                case TypeCode.Char:
                    return char.Parse(obj.ToString());
                case TypeCode.DBNull:
                    throw new NotSupportedException(string.Format("未处理的数据类型:{0}", type));
                case TypeCode.DateTime:
                    return DateTime.Parse(obj.ToString());//reader.GetDateTime(index);
                case TypeCode.Decimal:
                    return Decimal.Parse(obj.ToString());//reader.GetDecimal(index);
                case TypeCode.Double:
                    return double.Parse(obj.ToString());//reader.GetDouble(index);
                case TypeCode.Empty:
                    if (type.IsClass) return null; else return Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(type));
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                case TypeCode.UInt32:
                case TypeCode.UInt16:
                    return int.Parse(obj.ToString());//reader.GetInt64(index);
                case TypeCode.Object:
                    throw new NotSupportedException(string.Format("未处理的数据类型:{0}", type));
                case TypeCode.Single:
                    return float.Parse(obj.ToString());//reader.GetFloat(index);
                case TypeCode.String:
                    return obj.ToString();//reader.GetString(index);
                default:
                    throw new NotSupportedException(string.Format("未处理的数据类型:{0}", type));
            }
        }

        //private object GetBasic(object obj, Type type)
        //{
        //    if (obj == null) return obj;
        //    var typeCode = Type.GetTypeCode(type);
        //    switch (typeCode)
        //    {
        //        case TypeCode.Boolean:
        //            return bool.Parse(obj.ToString());//reader.GetBoolean(index);
        //        case TypeCode.Byte:
        //            return byte.Parse(obj.ToString());//reader.GetByte(index);
        //        case TypeCode.Char:
        //            return obj.ToString();//reader.GetString(index);
        //        case TypeCode.DBNull:
        //            if (type.IsClass) return null; else return Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(type));
        //        case TypeCode.DateTime:
        //            return DateTime.Parse(obj.ToString());//reader.GetDateTime(index);
        //        case TypeCode.Decimal:
        //            return Decimal.Parse(obj.ToString());//reader.GetDecimal(index);
        //        case TypeCode.Double:
        //            return double.Parse(obj.ToString());//reader.GetDouble(index);
        //        case TypeCode.Empty:
        //            if (type.IsClass) return null; else return Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(type));
        //        case TypeCode.Int16:
        //            return int.Parse(obj.ToString());//reader.GetInt16(index);
        //        case TypeCode.Int32:
        //            return int.Parse(obj.ToString());//reader.GetInt32(index);
        //        case TypeCode.Int64:
        //            return int.Parse(obj.ToString());//reader.GetInt64(index);
        //        case TypeCode.Object:
        //            throw new NotSupportedException("数据库转化类型异常");
        //        case TypeCode.SByte:
        //            return byte.Parse(obj.ToString());//reader.GetByte(index);
        //        case TypeCode.Single:
        //            return float.Parse(obj.ToString());//reader.GetFloat(index);
        //        case TypeCode.String:
        //            return obj.ToString();//reader.GetString(index);
        //        case TypeCode.UInt16:
        //            return int.Parse(obj.ToString());//reader.GetInt16(index);
        //        case TypeCode.UInt32:
        //            return int.Parse(obj.ToString());//reader.GetInt32(index);
        //        case TypeCode.UInt64:
        //            return int.Parse(obj.ToString());//reader.GetInt64(index);
        //        default:
        //            throw new NotSupportedException(string.Format("未处理的数据类型:{0}", type));
        //    }
        //}

        //private TResult GetUnKnow
    }
}
